<template>
  <!-- 【注】preview-box类名用于定位错误题目，不能修改 -->
  <div class='preview-box'
       ref='previewBoxRef'
       :class='{
         fixed: (displayCover && (coverSetting.bgImg || coverSetting.bgColor)) || // 用于展示封面
                showingMask // 用于展示图片/描述详情蒙层时， 底下页面不会滑动
       }'>
    <!-- 背景 -->
    <div class='box-bg'
         v-show='((bgSetting.bgType === 1 && bgSetting.bgImg) ||
                  (bgSetting.bgType === 2 && bgSetting.bgColor)
                 ) && !isEndSurvey'
        :class='{
          useBgImg: bgSetting.bgType === 1,
          useBgColor: bgSetting.bgType === 2
        }'
        :style='{
          backgroundColor: bgSetting.bgColor,
          backgroundImage: `url(${bgSetting.bgImg})`
        }'>
    </div>
    <!-- 问卷封面预览， 如果设置了背景图片，或背景色 -->
    <div class='box-cover'
        v-if='coverSetting.bgImg || coverSetting.bgColor'
        :class='{
          isSlide: coverSetting.startWay === 2, // 控制封面是否滑动显隐
          useBgImg: displayCover && coverSetting.bgType === 1,
          useBgColor: displayCover && coverSetting.bgType === 2,
          hideBg: !displayCover
        }'
        :style='{
          maxHeight: coverHeight,
          backgroundImage: `url(${coverSetting.bgImg})`,
          backgroundColor: coverSetting.bgColor
        }'
        @touchstart='touchstart'
        @touchmove='touchmove'
        @touchend='touchend'>
      <div class='cover-title'
            v-show='coverSetting.showTitle && displaySetting.showTitle'
            v-html='survey.richTextTitle'
            :class='{
              top: coverSetting.titleLocation === "top",
              center: coverSetting.titleLocation === "center",
              bottom: coverSetting.titleLocation === "bottom"
            }'
            :style='{
              color: coverSetting.titleFontColor,
              fontSize: coverSetting.titleFontSize + "px"
            }'>
      </div>
      <div class='cover-btn'
            v-show='coverSetting.startWay === 1'
            :style='{
              color: coverSetting.buttonFontColor,
              backgroundColor: coverSetting.buttonBaseColor
            }'
            @click='slideUpCover()'>
        {{coverSetting.buttonText}}
      </div>
      <div class='cover-slide'
            v-show='coverSetting.startWay === 2'>
        <span class='slide-text'>上滑开始</span>
        <span class='slide-icon'></span>
      </div>
    </div>
    <!-- 页面 -->
    <div class='box-page'
         v-show='!isEndSurvey'
        :class='{
          hideCover: !displayCover || (!coverSetting.bgImg && !coverSetting.bgColor),
          showPageBg: (bgSetting.bgType === 1 && bgSetting.bgImg) || (bgSetting.bgType === 2 && bgSetting.bgColor)
        }'>
      <!-- 问卷内容预览 -->
      <div class='survey-wrapper'
           v-show='!loading'
           :class='{
             showPageBg: (bgSetting.bgType === 1 && bgSetting.bgImg) || (bgSetting.bgType === 2 && bgSetting.bgColor)
           }'>
        <div class='survey-page-bg'
              :style='{opacity: bgSetting.bgOpacity / 100}'></div>
        <div class='survey-page'>
          <!-- 显示是预览测试模式 -->
          <div class='survey-test-tip' v-if='isTest'>当前为预览页面，回答将不记入结果</div>
          <!-- 页眉 -->
          <div class='survey-header'
               v-show='headerSetting.showHeader &&
                      (headerSetting.headerText || headerSetting.headerImg) &&
                      (!survey.pagingMode || (survey.pagingMode && currQaIndex === 0))'
               :class='{isTest: isTest}'>
            <!-- 文字 -->
            <div class='header-text'
                  v-show='headerSetting.headerType === 1 && headerSetting.headerText'
                  v-html='headerSetting.headerText'
                  :style='{backgroundColor: headerSetting.headerBgColor}'>
            </div>
            <!-- 图片 -->
            <img class='header-img'
                  v-show='headerSetting.headerType === 2 && headerSetting.headerImg'
                  :src='headerSetting.headerImg'>
          </div>
          <!-- 标题 -->
          <div class='survey-cover'
              v-show='survey.richTextTitle &&
                    !coverSetting.bgImg &&
                    !coverSetting.bgColor &&
                    (!survey.pagingMode || (survey.pagingMode && currQaIndex === 0))'
              v-html='survey.richTextTitle'>
          </div>
          <!-- 欢迎语 -->
          <div class='survey-accessText'
              v-show='survey.accessText &&
                      displaySetting.showWelcome &&
                      (!survey.pagingMode || (survey.pagingMode && currQaIndex === 0))'
              v-html='survey.accessText'>
          </div>
          <!-- 题目列表 -->
          <ul class='survey-question'>
            <!-- 【注】question-item 类名用于定位错误题目，不能修改 -->
            <li class='question-item'
                v-for='(qa, index) of qaList'
                :key='"qa" + index'
                v-show='!survey.pagingMode || (survey.pagingMode && currQaIndex === index)'>
              <!-- 题目标题 -->
              <div class='qa-title'>
                <div class='title-content' v-html='qa.topic'></div>
              </div>
              <!-- 单选题 -->
              <mobile-singleSelect
                v-if='qa.type === "RADIO"'
                :question='qa'>
              </mobile-singleSelect>
              <!-- 多选题 -->
              <mobile-multiSelect
                v-if='qa.type === "MULTIPLE"'
                :question='qa'>
              </mobile-multiSelect>
              <!-- 图片选择题 -->
              <mobile-picSelect
                v-if='qa.type === "PIC_CHOOSE"'
                :question='qa'>
              </mobile-picSelect>
              <!-- 图片投票题 -->
              <mobile-picVote
                v-if='qa.type === "PIC_VOTE"'
                :question='qa'>
              </mobile-picVote>
              <!-- 文字投票题 -->
              <mobile-textVote
                v-if='qa.type === "TEXT_VOTE"'
                :question='qa'>
              </mobile-textVote>
              <!-- 量表题 -->
              <mobile-scaling
                v-if='qa.type === "SCALE"'
                :question='qa'>
              </mobile-scaling>
              <!-- 单项填空题 -->
              <mobile-singleFill
                v-if='qa.type === "FILLS"'
                :question='qa'>
              </mobile-singleFill>
              <!-- 多项填空题 -->
              <mobile-multiFill
                v-if='qa.type === "MULTITERM_FILLS"'
                :question='qa'>
              </mobile-multiFill>
              <!-- 评价题 -->
              <mobile-rating
                v-if='qa.type === "EVALUATION"'
                :question='qa'>
              </mobile-rating>
              <!-- 打分题 -->
              <mobile-score
                v-if='qa.type === "GRADE"'
                :question='qa'>
              </mobile-score>
              <!-- 级联题 -->
              <mobile-cascader
                v-if='qa.type === "CASCADE"'
                :question='qa'>
              </mobile-cascader>
              <!-- 文件上传 -->
              <mobile-file
                v-if='qa.type === "FILE_UPLOAD"'
                :question='qa'
                :isTest='isTest'>
              </mobile-file>
            </li>
          </ul>
          <!-- 按钮 -->
          <div class='survey-btn-list'>
            <div class='btn-item prev'
                 v-show='survey.pagingMode && currQaIndex > 0'
                :style='{
                  color: buttonSetting.globalButtonColor,
                  borderColor: buttonSetting.globalButtonColor
                }'
                @click='showQa(-1)'>
              上一页
            </div>
            <div class='btn-item next'
                 v-show='survey.pagingMode && currQaIndex < qaList.length - 1'
                :style='{
                  backgroundColor: buttonSetting.globalButtonColor,
                  borderColor: buttonSetting.globalButtonColor
                }'
                @click='showQa(1)'>
              下一页
            </div>
            <div class='btn-item next'
                  v-show='(survey.pagingMode && currQaIndex >= qaList.length - 1) ||
                        !survey.pagingMode'
                  :style='{
                    backgroundColor: buttonSetting.globalButtonColor,
                    borderColor: buttonSetting.globalButtonColor
                  }'
                  @click='submitSurvey()'>
              {{buttonSetting.submitButtonText}}
            </div>
          </div>
        </div>
      </div>
    </div>
    <!-- 结束页 -->
    <div class='end-wrapper'
          v-show='isEndSurvey'
          :class='{
            useBgImg: endPageSetting.bgType === 1,
            useBgColor: endPageSetting.bgType === 2
          }'
          :style='{
            backgroundImage: `url(${endPageSetting.bgImg})`,
            backgroundColor: endPageSetting.bgColor
          }'>
      <div class='end-text'
            v-html='survey.closeText'
            :style='{
              color: endPageSetting.titleFontColor
            }'>
      </div>
    </div>
  </div>
</template>

<script>
import mobileSingleSelect from './components/mobile-singleSelect'
import mobileMultiSelect from './components/mobile-multiSelect'
import mobilePicSelect from './components/mobile-picSelect'
import mobilePicVote from './components/mobile-picVote'
import mobileTextVote from './components/mobile-textVote'
import mobileScaling from './components/mobile-scaling'
import mobileSingleFill from './components/mobile-singleFill'
import mobileMultiFill from './components/mobile-multiFill'
import mobileRating from './components/mobile-rating'
import mobileScore from './components/mobile-score'
import mobileCascader from './components/mobile-cascader'
import mobileFile from './components/mobile-file'
export default {
  name: 'surveyNewPaper',
  data () {
    return {
      surveyId: '',
      isTest: false,
      loading: true,
      setting: {
        coverSetting: '',
        endPageSetting: '',
        headerSetting: '',
        bgSetting: '',
        buttonSetting: '',
        displaySetting: ''
      },
      // 封面设置
      coverSetting: {
        bgType: 1, // 1 为封面背景使用图片  2 为封面背景使用颜色
        bgImg: '', // 封面背景图
        bgColor: '', // 封面背景色
        showTitle: true, // 是否显示标题
        titleLocation: 'top', // 标题显示位置
        titleFontSize: 24, // 标题字体大小
        titleFontColor: '#000000', // 标题颜色
        startWay: 1, // 开始方式 （点击按钮/向上滑动）
        buttonBaseColor: '#2672ff', // 按钮底色
        buttonFontColor: '#ffffff', // 按钮字体颜色
        buttonText: '立即开始' // 按钮字体内容
      },
      // 封底设置
      endPageSetting: {
        bgType: 1, // 1 为封底背景使用图片  2 为底面背景使用颜色
        bgImg: '', // 封底背景图
        bgColor: '', // 封底背景色
        titleFontColor: '#000000' // 标题颜色
      },
      // 页眉设置
      headerSetting: {
        showHeader: true,
        headerType: 1, // 1 为使用文字  2 为使用图片
        headerText: '',
        headerBgColor: '#eff4fe',
        headerImg: ''
      },
      // 背景设置
      bgSetting: {
        bgType: 1,
        bgColor: '',
        bgImg: '',
        bgOpacity: 100
      },
      // 按钮设置
      buttonSetting: {
        globalButtonColor: '#2672ff',
        startButtonText: '立即开始',
        submitButtonText: '提交'
      },
      // 显示设置
      displaySetting: {
        showQuestionNum: true,
        showTitle: true,
        showWelcome: true
      },
      survey: {
        surveyId: '1',
        title: '', // 问卷标题
        richTextTitle: '', // 展示的问卷标题
        accessText: '', // 问卷开始语
        closeText: '', // 问卷正常结束语
        advanceText: '', // 问卷提前结束语
        pagingMode: false // 为true时，一页展示一题
      },
      qaList: [],
      displayCover: true,
      coverHeight: '100vh',
      previewMobileUrl: 'https://www.baidu.com',
      startTime: null,
      showingMask: false,
      // 分页相关
      currQaIndex: 0,
      // 封面上滑相关
      coverClientY: 0,
      // 结束页相关
      isEndSurvey: false,
      // 验证相关
      /* eslint-disable */
      fillValidType: [
        {
          type: 'text',
          // 【注】此正则只判断是否含有表情，如果含有，就不是纯文本
          reg: /\uD83C[\uDF00-\uDFFF]|\uD83D[\uDC00-\uDE4F]/,
          tip: 'fill_text'
        },
        {
          type: 'number',
          reg: /^[0-9]*$/,
          tip: 'fill_number'
        },
        {
          type: 'en',
          reg: /^[a-zA-Z]*$/,
          tip: 'fill_en'
        },
        {
          type: 'cn',
          reg: /^[\u4e00-\u9fa5]*$/,
          tip: 'fill_cn'
        },
        { 
          type: 'email',
          reg: /^\w+((-w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/,
          tip: 'fill_email'
        },
        {
          type: 'phone',
          reg: /^1\d{10}$/,
          tip: 'fill_phone'
        },
        {
          type: 'url',
          reg: /^(http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?$/,
          tip: 'fill_url'
        },
        {
          type: 'indentification',
          reg: /^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$|^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/,
          tip: 'fill_indentification'
        }
      ]
      /* eslint-disable */
    }
  },
  components: {
    mobileSingleSelect,
    mobileMultiSelect,
    mobilePicSelect,
    mobilePicVote,
    mobileTextVote,
    mobileScaling,
    mobileSingleFill,
    mobileMultiFill,
    mobileRating,
    mobileScore,
    mobileCascader,
    mobileFile
  },
  methods: {
    touchstart (e) {
      this.coverClientY = e.touches[0].clientY
      // console.log('touchstart', this.coverClientY)
    },
    touchmove (e) {
      e.preventDefault()
    },
    touchend (e) {
      let newClientY = e.changedTouches[0].clientY
      // console.log('touchend', newClientY)
      if (this.coverSetting.startWay === 2 && this.coverClientY - newClientY > 20) {
        this.slideUpCover()
      }
    },
    showQa (step) {
      this.checkAnswerAndGetScore([this.qaList[this.currQaIndex]], result => {
        this.currQaIndex += step
      })
    },
    closePreview () {
      this.$emit('close')
    },
    // 上滑隐藏封面页，展示题目页
    slideUpCover () {
      this.displayCover = false
      this.coverHeight = '0px'
    },
    // 获取问卷基本信息
    getSurveyDetail () {
      let url = `${this.SERVICE_UPGRADE_SURVEY}/${this.surveyId}`
      this.$get(url).then(res => {
        if (res.code === 200) {
          if (res.data) {
            this.survey = res.data
          }
        } else {
          this.$toast(res.message)
        }
        // console.log('survey: ', this.survey)
      })
    },
    // 获取设置接口
    getSetting () {
      let url = `${this.SERVICE_UPGRADE_SURVEY}/setting/${this.surveyId}`
      this.$get(url).then(res => {
        if (res.code === 200) {
          if (res.data) {
            // console.log('res: ', res.data)
            let data = res.data
            for (let key of Object.keys(this.setting)) {
              if (data[key]) {
                this[key] = data[key]
              }
            }
          }
        } else {
          this.$toast(res.message)
        }
        this.getQaList()
      })
    },
    // 获取问卷的信息和题目列表
    getQaList () {
      let url = `${this.SERVICE_UPGRADE_SURVEY}/questions/${this.surveyId}`
      this.$get(url).then(res => {
        if (res.code === 200) {
          if (res.data) {
            let qaList = res.data
            // 初始化题目结构，用于后续的验证和分数结算
            qaList.forEach(qa => {
              // 给所有选项添加isSelected字段, resultText字段
              qa.optionList.forEach(option => {
                option.isSelected = false // 该字段用于选择类题型是否被选中
                option.resultText = '' // 该字段用于填空类、选择类其他选项输入的内容
              })
              // 如果是图片投票题、文字投票题，添加投票结果展示字段
              if (qa.type === 'PIC_VOTE' || qa.type === 'TEXT_VOTE') {
                qa.optionList.forEach(option => {
                  option.votePercentage = 0
                  option.voteCount = 0
                })
              }
              // 如果是单项填空题, 添加答案字段
              if (qa.type === 'FILLS') {
                qa.resultText = ''
              }
              // 添加验证提示语字段
              qa.validType = ''
              if (qa.type === 'MULTITERM_FILLS') {
                qa.optionList.forEach(option => {
                  option.validType = ''
                  let extendAttr = JSON.parse(option.extendAttr || '{}')
                  option.validate = extendAttr.validate
                  option.minLength = parseInt(extendAttr.minLength || 0)
                  option.maxLength = extendAttr.maxLength ? parseInt(extendAttr.maxLength) : null
                  option.isOptional = extendAttr.isOptional
                  // 如果选项是选填的， 在选项的标题后添加（选填）
                  if (option.isOptional) {
                    let marker = '<span class="title-optional">(选填)</span>'
                    option.title = this.markEndOfRichStr(option.title, marker)
                  }
                })
              }
              // 如果时评价题，添加选择标签和自定义评价内容字段
              if (qa.type === 'EVALUATION') {
                qa.labels = []
                qa.resultText = ''
                qa.useWrite = false
              }
              // 如果是打分题，需要初始化每个打分选项的数据
              if (qa.type === 'GRADE') {
                qa.optionList.forEach(option => {
                  option.selectedScore = -1
                  option.activeIndex = -1
                  option.scoreLevel = -1
                })
              }
              // 如果是级联题
              if (qa.type === 'CASCADE') {
                qa.level1 = ''
                qa.level1Name = ''
                qa.level2 = ''
                qa.level2Name = ''
                qa.level3 = ''
                qa.level3Name = ''
                qa.level4 = ''
                qa.level4Name = ''
                // 获取设置项
                qa.optionList = [
                  { listId: '1', title: '请选择' },
                  { listId: '2', title: '请选择' }
                ]
                qa.optionData = [
                  {
                    optionId: '1',
                    title: '选项1',
                    children: [
                      {
                        optionId: '11',
                        title: '选项1-1',
                        children: []
                      }
                    ]
                  }
                ]
                // 如果是保存的数据，从扩展字段中获取配置项
                if (qa.extendAttr) {
                  qa = Object.assign(qa, JSON.parse(qa.extendAttr))
                }
              }
              // 如果是文件上传题
              if (qa.type === 'FILE_UPLOAD') {
                qa.fileArr = []
                qa.maxCount = 1
                qa.typeArr = ['all']
                // 如果是保存的数据，从扩展字段中获取配置项
                if (qa.extendAttr) {
                  qa = Object.assign(qa, JSON.parse(qa.extendAttr))
                }
              }
            })
            this.qaList = qaList
            this.updateQaOrdinal()
            this.updateQaRequired()
            this.loading = false
          } else {
            this.loading = false
          }
        } else {
          this.$toast(res.message)
          this.loading = false
        }
      })
    },
    // 在富文本尾部添加标记
    markEndOfRichStr (richStr, marker) {
      // richStr是富文本，找出所有文本节点尾部
      // eg: <div><p><span>我是内容</span></p></div>我是内容2  => [容</span></p></div>]
      let matchResult = richStr.match(/[^>](<[^>]+>)+/g)
      // 如果没有匹配项，则直接拼接在尾部
      if (!matchResult) {
        richStr = richStr + marker
      // 如果有匹配项，找到最后的匹配项
      } else {
        let lastMatchStr = matchResult[matchResult.length - 1]
        // 判断最后的文本节点后，是否还有纯文本
        let lastMatchIndex = richStr.lastIndexOf(lastMatchStr)
        let lastStr = richStr.slice(lastMatchIndex)
        // 如果后面还有纯文本，直接拼接在尾部
        if (lastMatchStr !== lastStr) {
          richStr = richStr + marker
        // 如果没有纯文本， 则插入到最后的文本节点中
        } else {
          let text1 = richStr.slice(0, lastMatchIndex + 1)
          let text2 = richStr.slice(lastMatchIndex + 1)
          richStr = text1 + marker + text2
        }
      }
      return richStr
    },
    // 根据主题设置是否显示题目序号、题目的顺序以及序号显隐情况，更新题目的序号
    updateQaOrdinal () {
      let ordinal = 1
      this.qaList.forEach(qa => {
        if (this.displaySetting.showQuestionNum) {
          if (qa.showNumber) {
            qa.ordinal = ordinal
            ordinal++
          } else {
            qa.ordinal = ''
          }
        } else {
          qa.ordinal = ''
        }
        this.updateTopicOrdinal(qa)
      })
      console.log('final qaList: ', this.qaList)
    },
    // 根据ordinal字段，在题目的标题中显隐序号
    updateTopicOrdinal (qa) {
      let topic = qa.topic
      let ordinal = qa.ordinal
      let startLabel = '<span class="ordinal">'
      let endLabel = '</span>'
      let startIndex = topic.indexOf(startLabel)
      // 如果需要隐藏序号
      if (!ordinal) {
        // 如果原本有序号
        if (startIndex !== -1) {
          let endIndex = topic.indexOf(endLabel, startIndex)
          let text1 = topic.slice(0, startIndex)
          let text2 = topic.slice(endIndex + endLabel.length)
          qa.topic = text1 + text2
        }
      // 如果需要显示序号
      } else {
        // 如果原本有序号
        if (startIndex !== -1) {
          let endIndex = topic.indexOf('</span>', startIndex)
          let text1 = topic.slice(0, startIndex + startLabel.length)
          let text2 = topic.slice(endIndex)
          qa.topic = text1 + qa.ordinal + '.' + text2
        // 如果原本没有序号, 在第一个文本元素中插入序号
        } else {
          // 如果文本元素包裹在html标签中
          if (/^<[^>]+>/.test(topic)) {
            let matchResult = topic.match(/>[^<]/)
            console.log('matchResult: ', matchResult)
            let insertIndex = 0
            if (matchResult && matchResult.index) {
              insertIndex = matchResult.index + 1
            }
            let text1 = topic.slice(0, insertIndex)
            let text2 = topic.slice(insertIndex)
            let insertText = startLabel + qa.ordinal + '.' + endLabel
            qa.topic = text1 + insertText + text2
          // 如果文本元素没有被html标签包裹
          } else {
            qa.topic = startLabel + qa.ordinal + '.' + endLabel + qa.topic
          }
        }
      }
    },
    // 显示题目是否必填
    updateQaRequired () {
      this.qaList.forEach(qa => {
        // 如果是必填题，在标题尾部插入'*'
        if (qa.isRequired) {
          let marker = '<span class="qa-required">*</span>'
          qa.topic = this.markEndOfRichStr(qa.topic, marker)
        }
      })
    },
    // 验证各题目是否符合要求, 并计算答案，得到分数结果
    checkAnswerAndGetScore (qaList, cb) {
      let isValid = false
      let length = qaList.length
      let result = {
        surveyId: this.surveyId,
        questionResults: []
      }
      for (let i = 0; i < length; i++) {
        let qa = qaList[i]
        let optionResults = []
        // 如果是单选题、多选题、图片选择题、图片投票题、文字投票题、量表题、评价题
        if (qa.type === 'RADIO' ||
            qa.type === 'MULTIPLE' ||
            qa.type === 'PIC_CHOOSE' ||
            qa.type === 'PIC_VOTE' ||
            qa.type === 'TEXT_VOTE' ||
            qa.type === 'SCALE' ||
            qa.type === 'EVALUATION') {
          qa.optionList.forEach(option => {
            if (option.isSelected) {
              // 如果该选项是其他选项
              if (option.isOther) {
                // 如果没有输入填空选项， 则不符合要求
                if (!option.resultText) {
                  isValid = true
                  qa.validType = 'otherOptionEmpty'
                }
                optionResults.push({
                  optionId: option.optionId,
                  resultText: option.resultText
                })
              } else {
                // 如果是评价题
                if (qa.type === 'EVALUATION') {
                  optionResults.push({
                    optionId: option.optionId,
                    labels: qa.labels,
                    resultText: (qa.useWrite && qa.resultText) ? qa.resultText : null
                  })
                } else {
                  optionResults.push({
                    optionId: option.optionId
                  })
                }
              }
            }
          })
          // 如果是评价题，必填且至少选择一个标签， 若没有选择标签，则不符合要求
          if (qa.type === 'EVALUATION' && qa.isRequired) {
            let extendAttr = JSON.parse(qa.extendAttr || '{}')
            if (extendAttr.mustChooseOneLabel && !qa.labels[0]) {
              isValid = true
              qa.validType = 'rating_label'
            }
          }
          // 如果是必填题，且没有选择选项，则不符合要求
          if (qa.isRequired && !optionResults[0]) {
            isValid = true
            qa.validType = 'required'
          }
        // 如果是单项填空题
        } else if (qa.type === 'FILLS') {
          // 如果没有输入答案
          if (!qa.resultText) {
            // 如果是必填题， 则不符合要求
            if (qa.isRequired) {
              isValid = true
              qa.validType = 'required'
            }
          // 验证答案是否符合要求
          } else {
            let extendAttr = JSON.parse(qa.extendAttr || '{}')
            // 验证答案长度
            let minLength = parseInt(extendAttr.minLength || 0)
            let maxLength = extendAttr.maxLength ? parseInt(extendAttr.maxLength) : null
            let length = qa.resultText.length
            if ((length < minLength) || (maxLength && length > maxLength)) {
              isValid = true
              qa.validType = 'fill_length'
            }
            // 验证答案格式
            let validate = extendAttr.validate
            // 格式不限不用验证
            if (validate && validate !== 'none') {
              let validItem = this.fillValidType.filter(valid => valid.type === validate)[0]
              // 如果是纯文本，不能包含表情
              if (validate === 'text') {
                if (validItem.reg.test(qa.resultText)) {
                  isValid = true
                  qa.validType = validItem.tip
                }
              // 其他格式验证
              } else {
                if (!validItem.reg.test(qa.resultText)) {
                  isValid = true
                  qa.validType = validItem.tip
                }
              }
            }
            optionResults.push({
              optionId: qa.optionList[0].optionId,
              resultText: qa.resultText || null
            })
          }
        // 如果是多项填空题
        } else if (qa.type === 'MULTITERM_FILLS') {
          // 遍历所有填空项，进行验证
          qa.optionList.forEach(option => {
            // 如果没有输入答案
            if (!option.resultText) {
              if (qa.isRequired && !option.isOptional) {
                isValid = true
                option.validType = 'required'
              }
            // 验证答案是否符合要求
            } else {
              // 验证答案长度
              let length = option.resultText.length
              if ((length < option.minLength) || (option.maxLength && length > option.maxLength)) {
                isValid = true
                option.validType = 'fill_length'
              }
              // 验证答案格式
              let validate = option.validate
              if (validate && validate !== 'none') {
                let validItem = this.fillValidType.filter(valid => valid.type === validate)[0]
                // 如果是纯文本，不能包含表情
                if (validate === 'text') {
                  console.log('option.resultText: ', option.resultText)
                  if (validItem.reg.test(option.resultText)) {
                    isValid = true
                    option.validType = validItem.tip
                  }
                // 其他格式验证
                } else {
                  if (!validItem.reg.test(option.resultText)) {
                    isValid = true
                    option.validType = validItem.tip
                  }
                }
              }
              optionResults.push({
                optionId: option.optionId,
                resultText: option.resultText || null
              })
            }
          })
          // 只要多项填空题验证不符合要求，错误类型统一为multiFill_related
          if (isValid) {
            qa.validType = 'multiFill_related'
          }
        // 如果是打分题
        } else if (qa.type === 'GRADE') {
          // 遍历每个打分项，获取打分层级
          qa.optionList.forEach(option => {
            // 如果打分题是必填，且没有选择打分层级，则不符合要求
            if (qa.isRequired && option.scoreLevel < 0) {
              isValid = true
              qa.validType = 'required'
            }
            optionResults.push({
              optionId: option.optionId,
              scoreLevel: option.scoreLevel
            })
          })
        // 如果是级联题
        } else if (qa.type === 'CASCADE') {
          // 如果设置了必填，则必须选择完所有可选层级内容
          if (qa.isRequired) {
            if ((qa.optLev1[0] && !qa.level1Name) ||
                (qa.optLev2[0] && !qa.level2Name) ||
                (qa.optLev3[0] && !qa.level3Name) ||
                (qa.optLev4[0] && !qa.level4Name)
            ) {
              isValid = true
              qa.validType = 'required'
            }
          }
          let resultText = JSON.stringify({
            level1Name: qa.level1Name,
            level2Name: qa.level2Name,
            level3Name: qa.level3Name,
            level4Name: qa.level4Name
          })
          optionResults.push({
            resultText: resultText
          })
        // 如果是文件上传
        } else if (qa.type === 'FILE_UPLOAD') {
          // 如果设置了必填，则至少上传一个文件
          if (qa.isRequired && !qa.fileArr[0]) {
            isValid = true
            qa.validType = 'required'
          }
          optionResults.push({
            resultText: JSON.stringify(qa.fileArr)
          })
        }
        // 如果当前题目不符合要求，直接显示，不再继续验证和计算
        if (isValid) {
          break
        // 如果当前题目符合要求，得到该题目的答案，继续下一题
        } else {
          // 只有输入答案的题目，不需要提交给接口
          if (optionResults[0]) {
            result.questionResults.push({
              questionId: qa.questionId,
              optionResults: optionResults
            })
          }
        }
      }
      // console.log('=== result ===', result)
      // 如果有不符合要求的题目, 则直接定位到该题目的位置
      if (isValid) {
        this.$nextTick(() => {
          this.focusInvalidQuestion()
        })
      } else {
        if (cb && typeof cb === 'function') {
          console.log('result: ', result)
          cb.call(this, result)
        }
      }
    },
    submitSurvey () {
      this.checkAnswerAndGetScore(this.qaList, result => {
        console.log('=== submit result ===: ', result)
        // 如果是预览模式, 直接展示结束页
        if (this.isTest) {
          this.isEndSurvey = true
        // 否则提交答案，替换为结束页
        } else {
          // 计算提交的时间
          let param = result
          param.startTime = this.getFormatedTime(this.startTime, '-', 'second')
          param.endTime = this.getFormatedTime(new Date(), '-', 'second')
          param.openid = sessionStorage.getItem('openid')
          param.wxAppid = sessionStorage.getItem('appid')
          param.unionId = this.$route.query.unionId || null
          param.unionType = this.$route.query.unionType || null
          console.log('param: ', param)
          this.$_load.show()
          let url = `${this.SERVICE_UPGRADE_SURVEY}/answer/submit`
          this.$posts(url, param).then(res => {
            if (res.code === 200) {
              if (this.$route.query.unionType) {
                this.$router.replace({ name: 'surveyNewEnd', query: { unionType: this.$route.query.unionType } })
                switch (this.$route.query.unionType) {
                  case 'ON_LINE_MEETING':
                  case 'OFF_LINE_MEETING':
                    this.operateTrack(this.survey.type)
                    break
                }
              } else {
                this.$router.replace({ name: 'surveyNewEnd' })
              }
            } else {
              this.$toast(res.message)
            }
            this.$_load.hide()
          })
        }
      })
    },
    // 定位到不符合答案要求的题目
    focusInvalidQuestion () {
      // 定位到第一个错误提示DOM
      let validTipDOM = document.querySelectorAll('.valid-tip-box')[0]
      if (!validTipDOM) {
        return false
      }
      // 获取该提示对应题目的位置DOM
      let parent = validTipDOM.offsetParent
      if (!parent) {
        return false
      }
      while (parent && parent.className !== 'question-item') {
        parent = parent.offsetParent
      }
      let validQaDOM = parent
      // 获取该题目到页面顶部的距离
      let top = validQaDOM.offsetTop
      let qaParent = validQaDOM.offsetParent
      while (qaParent && qaParent.className !== 'preview-box') {
        top += qaParent.offsetTop
        qaParent = qaParent.offsetParent
      }
      let ValidQaTop = top - 10 // 10为定位后题目到顶部的间距
      // console.log('ValidQaTop', ValidQaTop)
      // console.log('qaParent', qaParent)
      // console.log('documentElement scrollTop: ', document.documentElement.scrollTop)
      // console.log('body scrollTop: ', document.body.scrollTop)
      let scrollBox = null
      if (document.documentElement.scrollTop) {
        scrollBox = document.documentElement
      } else if (document.body.scrollTop) {
        scrollBox = document.body
      }
      if (scrollBox) {
        this.scrollDOM(scrollBox, ValidQaTop, 200)
      }
    },
    // 互动统计
    operateTrack (operateType) {
      let url = `${this.SERVICE_PORTAL}/meeting/${sessionStorage.getItem('appid')}/${this.$route.query.unionId}/operate/${sessionStorage.getItem('openid')}/${operateType}`
      this.$posts(url).then(res => {
        console.log('operateTrack', res.message)
      })
    },
    init () {
      this.getSurveyDetail()
      this.getSetting()
    }
  },
  created () {
    this.surveyId = this.$route.params.surveyId
    this.isTest = this.$route.query.test
    this.startTime = new Date()
    this.init()
  }
}
</script>

<style lang='stylus' scoped>
.preview-box
  position: relative;
  width: 100vw
  &.fixed
    position fixed
    height:100vh
  // 背景
  .box-bg
    position fixed
    top 0
    left 0
    width 100vw
    height 100vh
    &.useBgImg
      bgCover()
      background-color #fff !important
    &.useBgColor
      background-image none !important
  // 封面
  .box-cover
    position relative
    height 100vh
    overflow hidden
    &.isSlide
      transition max-height 0.3s ease
    &.useBgImg
      bgCover()
      background-color #fff !important
    &.useBgColor
      background-image none !important
    &.hideBg
      opacity 0
    .cover-title
      position absolute
      left 20px
      right 20px
      max-height 260px
      overflow hidden
      word-break break-all
      &.top
        top 40px
      &.center
        top 50%
        transform translateY(-50%)
      &.bottom
        bottom 120px
    .cover-btn
      position absolute
      bottom 40px
      left 20px
      right 20px
      height 40px
      line-height 40px
      border-radius 6px
      text-align center
      cursor pointer
    .cover-slide
      position absolute
      bottom 0
      left 0
      right 0
      height 80px
      display flex
      flex-direction column
      align-items center
      justify-content center
      .slide-text
        color #fff
        cursor pointer
        margin-bottom 10px
      .slide-icon
        width 16px
        height 16px
        cursor pointer
        background url('~assets/img/survey2.0/message_ic_up_pass@2x.png') no-repeat 0 0 / 100%
  // 页面
  .box-page
    position relative
    z-index 1
    height 100vh
    box-sizing border-box
    overflow hidden
    &.hideCover
      height auto
      &.showPageBg
        padding 10px 10px 0
    .survey-wrapper
      position relative
      box-sizing border-box
      min-height 100vh
      &.showPageBg
        min-height calc(100vh - 10px)
      .survey-page-bg
        position absolute
        left 0
        right 0
        top 0
        bottom 0
        background #fff
      .survey-page
        position relative
        z-index 1
        padding 20px 15px
        // scroll()
        box-sizing border-box
        .survey-test-tip
          background #ffbe3a
          font-size 14px
          text-align center
          color #fff
          padding 10px 0
          margin -20px -15px 20px
        .survey-header
          margin -20px -15px 20px
          // &.isTest
          //   margin-top 0
          .header-text
            padding 10px 15px
            line-height 1.5
            font-size 14px
          .header-img
            width 100%
        .survey-cover
          margin-bottom 20px
          word-break break-all
        .survey-accessText
          margin-bottom 20px
          font-size 14px
          word-break break-all
        .survey-question
          .question-item
            position relative
            margin-bottom 30px
            .qa-title
              display flex
              .title-ordinal
                flex none
                margin-right 5px
                line-height 1.5
              .title-content
                flex 1
                line-height 1.5
                >>> .ordinal
                  color #333 !important
                  margin-right 5px
                >>> .qa-required
                  position relative
                  top -1px
                  color #ff6d56
                  margin-left 2px
                >>> img, >>> iframe, >>> video
                  max-width 100% !important
        .survey-btn-list
          display flex
          height 34px
          .btn-item
            flex 1
            border-radius 4px
            box-sizing border-box
            line-height 34px
            text-align center
            cursor pointer
            &.prev
              margin-right 5px
              border 1px solid rgb(38, 114, 255)
              background #fff
              color rgb(38, 114, 255)
            &.next
              background rgb(38, 114, 255)
              color #fff
              border 1px solid rgb(38, 114, 255)
  .end-wrapper
    height 100vh
    padded_box(border-box, 15px)
    &.useBgImg
      bgCover()
      background-color #fff !important
    &.useBgColor
      background-image none !important
    .end-text
      font-size 14px
      line-height 1.5
</style>
